package dotdashdot.bradz.trendsettr;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.cookie.Cookie;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

public class ClassNetworkHelper {

	ClassHttpHelper helper;
	private Context context;
	private boolean pass_class;
	private Class<?> next_activity;
	private String post_controller;
	private boolean applying;
	private ClassUberLogger logger;
	//private ApplicationGlobalVars globals;
	
	ClassNetworkHelper(Context context, String base_url, ApplicationGlobalVars globals){
		this.context = context;
		helper = new ClassHttpHelper(base_url,globals);
		applying = false;
		logger = new ClassUberLogger("ClassNetworkHelper");
	}
	
	ClassNetworkHelper(Context context, ApplicationGlobalVars globals){
		this.context = context;
		//http://ec2-54-88-83-216.compute-1.amazonaws.com:3000/
		helper = new ClassHttpHelper("http://ec2-54-88-83-216.compute-1.amazonaws.com",globals);
		//helper = new ClassHttpHelper("http://ec2-54-88-83-216.compute-1.amazonaws.com:3000/",globals);
		applying = false;
		logger = new ClassUberLogger("ClassNetworkHelper");
	}
	
	public boolean applying(){
		return applying;
	}
	
	public void log_out_network(Handler handler){
		log_out_network_task login = new log_out_network_task();
		login.handler = handler;
		login.execute();
		logger.info("Logging out of network");
	}
	
	public void log_into_network(Class<?> next_activity,List<NameValuePair> pairs, boolean test_login){
		pass_class = true;
		this.next_activity = next_activity;
		log_into_network_task login = new log_into_network_task();
		login.test_login = test_login;
		login.execute(pairs.toArray(new NameValuePair[pairs.size()]));
		logger.info("Logging into network");
	}
	
	public void log_into_network(List<NameValuePair> pairs){
		pass_class = false;
		new log_into_network_task().execute(pairs.toArray(new NameValuePair[pairs.size()]));
		logger.info("Logging into network alt");
	}
	
	public void post_network(List<NameValuePair> pairs, String post_controller, Handler handler){
		this.post_controller = post_controller;
		post_network_task task = new post_network_task();
		task.handler = handler;
		logger.info("Posting to network");
		task.execute(pairs.toArray(new NameValuePair[pairs.size()]));
	}
	
	public void post_network(List<NameValuePair> pairs, String post_controller, ClassTrendResultContainer result_container, Handler handler){
		this.post_controller = post_controller;
		post_network_task task = new post_network_task();
		task.trend_container = result_container;
		task.handler = handler;
		logger.info("Posting to network alt");
		task.execute(pairs.toArray(new NameValuePair[pairs.size()]));
	}
	
	public void get_all_from_network_set_trend(ClassTrendingContainer container, Handler handler){
		get_from_network_task task = new get_from_network_task();
		task.handler = handler;
		task.set_trend = true;
		logger.info("Get request from set trend");
		task.execute(container);
	}
	
	public void get_all_from_network_see_trend(ClassTrendingContainer container, Handler handler){
		get_from_network_task task = new get_from_network_task();
		task.handler = handler;
		task.set_trend = false;
		logger.info("Get request from see trend");
		task.execute(container);
	}
	
	public void get_all_from_network_start_trend(ClassTrendingContainer container, Handler handler){
		get_from_network_task task = new get_from_network_task();
		task.request_url = "/trends";
		task.handler = handler;
		task.set_trend = true;
		logger.info("Get request from see trend");
		task.execute(container);
	}
	
	public void get_all_from_network_trend_history(ClassGraphInfo info, Handler handler){
		load_graph_info_task task = new load_graph_info_task();
		task.handler = handler;
		task.info = info;
		logger.info("Get request network history");
		task.execute(info);
	}
	
	public void apply_for_credentials(ClassUserCredentials credentials, Handler handler){
		applying = true;
		apply_for_credentials credentials_task = new apply_for_credentials();
		credentials_task.handler = handler;
		credentials_task.credentials = credentials;
		logger.info("Get request credentials");
		credentials_task.execute();
	}
	
	private class load_graph_info_task extends AsyncTask<ClassGraphInfo, Void, Void> {
		
		Handler handler = null;
		ClassGraphInfo info = null;
		JSONObject trend = null;
		JSONArray result_array = null;
		String controller = "/votes/day";

		@Override
        protected void onPreExecute() {
			logger.info("Async graph info init");
		}
		
		@Override
		protected Void doInBackground(ClassGraphInfo... params) {
			synchronized (helper) {
			info = params[0];
			try {
				//result_array = new JSONArray(helper.getResponsefromURL("/votes/"+info.trend+"/day"));
				ArrayList<NameValuePair> post_data = new ArrayList<NameValuePair>();
		    	post_data.add(new BasicNameValuePair("trendName",info.trend));
				result_array = new JSONArray(helper.postResponsefromURL(controller, post_data));
				
				logger.info("Received response from HttpHelper");
				for(int i = 0; i < result_array.length();i++){
					
					trend = result_array.getJSONObject(i);
					
					Timestamp date = new Timestamp(Long.parseLong(trend.get("date").toString()));
					int ups = Integer.parseInt(trend.get("votes").toString());
					int downs = Integer.parseInt(trend.get("downvotes").toString());
					
					logger.info("Timestamp: " + date.toString());
					logger.info("Ups: " + ups);
					logger.info("Downs: " + downs);
					
					info.add_graph_point(new ClassGraphData(date,ups,downs));
				}
			} catch (Exception e) {
				// TODO Auto-generated catch block
				logger.error("Error: " + e);
				e.printStackTrace();
			}
			}
			return null;
		}
		
		@Override
	    protected void onPostExecute(Void arg0) {
			 //The data needs to be saved into the database here...
			if(handler != null){
				logger.info("Returning data with handler...");
				handler.sendEmptyMessage(1);
			}else{
				logger.error("Hander is null! Cannot return data!");
			}
		}
		
	}
	
	private class get_from_network_task extends AsyncTask<ClassTrendingContainer, Void, Void> {
		
		Handler handler = null;
		boolean set_trend = false;
		ClassTrendingContainer network_container = null;
		String request_url = "";
		
		JSONObject trend = null;
		JSONArray result_array = null;
		
		@Override
        protected void onPreExecute() {
			logger.info("Get from network init");
		}
		
		@Override
		protected Void doInBackground(ClassTrendingContainer... container) {
			synchronized (helper) {
			network_container = container[0];
			
			try {
				if(set_trend && request_url.equals("")){
					request_url = "/trends/novotes";
				}else if(request_url.equals("")){
					request_url = "/trends/votes";
				}	
				logger.info("Sending request URL: " + request_url);
				result_array = new JSONArray(helper.getResponsefromURL(request_url));
				logger.info("Received data from HttpHelper");
				for(int i = 0; i < result_array.length();i++){
					trend = result_array.getJSONObject(i);
					
					logger.info("Data: " + trend.toString());
					
					String topic_name = trend.get("topicName").toString();
					String trend_name = trend.get("trendName").toString();
					logger.info("Topic: " + topic_name);
					logger.info("Trend: " + trend_name);
					int ups,downs,total;
					String meta_summary = "";
					String user_picture = "";
					ups=downs=total=0;
					
					if(!set_trend){
						logger.info("Votes: " + trend.get("votes").toString());
						logger.info("Downvotes: " + trend.get("downvotes").toString());
						
						ups = Integer.parseInt(trend.get("votes").toString().length()<1?"0":trend.get("votes").toString());
						downs = Integer.parseInt(trend.get("downvotes").toString().length()<1?"0":trend.get("downvotes").toString());
						total = ups + downs;
						
						meta_summary = trend.get("meta_summary").toString();
						
						if(trend.has("picture")){
							user_picture = trend.get("picture").toString();
						}
					}
					Timestamp created = new Timestamp(Long.parseLong(trend.get("created").toString()));
					
					logger.info("Timestamp: " + created);
					if(!set_trend){
						logger.info("Ups: " + ups);
						logger.info("Downs: " + downs);
					}
					network_container.add_topic(topic_name);
					
					if(set_trend){
						network_container.get_topic(topic_name).add_trend(user_picture,trend_name, meta_summary, "google.com",total,ups,created);
					}else{
						int uservote = Integer.parseInt(trend.get("voted").toString());
						logger.info("UserVote: " + uservote);
						network_container.get_topic(topic_name).add_trend(user_picture,trend_name, meta_summary, "google.com",total,ups,uservote,created);
					}
				}
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					logger.error("Invalid JSON object returned! Error: " + e);
					e.printStackTrace();
				}
			}
			return null;
		}
		
		@Override
	    protected void onPostExecute(Void arg0) {
			 //The data needs to be saved into the database here...
			if(handler != null){
				logger.info("Returning data with handler...");
				handler.sendEmptyMessage(0);
			}else{
				logger.error("Hander is null! Cannot return data!");
			}
		}
	}
	
	//Make sure that the network is active and working...
	private class post_network_task extends AsyncTask<NameValuePair, Void, Void> {
		
		ClassTrendResultContainer trend_container = null;
		String response = "";
		Handler handler = null;
		
		@Override
        protected void onPreExecute() {
			logger.info("Post to network init");
		}
		
		@Override
		protected Void doInBackground(NameValuePair... pairs) {
			synchronized (helper) {
			//Needs error handling here
				logger.info("Sending Post Data");
				logger.info("Controller: " + post_controller);
				response = helper.postResponsefromURL(post_controller, new ArrayList<NameValuePair>(Arrays.asList(pairs)));
				logger.info("Received response from HttpHelper");
			}

			return null;
		}
		
		@Override
	    protected void onPostExecute(Void v) {
			logger.info("Received Trend Info");
			logger.info("Result Container: " + trend_container == null?"False":"True");
			try {
				JSONObject result_object = new JSONObject(response);
				if(trend_container != null){
					logger.info("Response: " + response);
					String votes = result_object.get("votes").toString() == "" ? "0": result_object.get("votes").toString();
					String downvotes = result_object.get("downvotes").toString() == "" ? "0": result_object.get("downvotes").toString();
					int up = Integer.valueOf(votes);
					int down = Integer.valueOf(downvotes);
					int total = up+down;
					int up_percent = (int)(((float) up / (float) total) * 100);
					int down_percent = (int)(((float) down / (float) total) * 100);
					
					if((trend_container.voted_for && up_percent >= down_percent) || (!trend_container.voted_for && up_percent <= down_percent)){
						//trend_container.trend_layout.setBackgroundDrawable(trend_container.background_yes);
						trend_container.showable_yes.setVisibility(View.VISIBLE);
						
						trend_container.background_yes.setVisibility(View.VISIBLE);
					}else{
						//trend_container.trend_layout.setBackgroundDrawable(trend_container.background_no);
						trend_container.showable_no.setVisibility(View.VISIBLE);
						
						trend_container.background_no.setVisibility(View.VISIBLE);
					}
		    		
					trend_container.yes.setText(up_percent+"%");
					trend_container.no.setText(down_percent+"%");
		    		
					trend_container.yes.setVisibility(View.VISIBLE);
		    		trend_container.no.setVisibility(View.VISIBLE);
		    		trend_container.disclaimer.setVisibility(View.INVISIBLE);
				}
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
    		if(handler != null){
				logger.info("Returning data with handler...");
				handler.sendEmptyMessage(6);
			}else{
				logger.error("Hander is null! Cannot return data!");
			}
		}
	}
	
	//Make sure that the network is active and working...
	private class log_into_network_task extends AsyncTask<NameValuePair, Void, Void> {
		
		boolean intent_started;
		boolean returned_error;
		boolean test_login;
		
		@Override
        protected void onPreExecute() {
			intent_started = returned_error = false;
			logger.info("Log into network init");
		}
		
		@Override
		protected Void doInBackground(NameValuePair... pairs) {
			synchronized (helper) {
			//Saves the new user. If the user isn't new, sends back an error with the user in the db
			logger.info("Sending post");
			helper.postResponsefromURL("/user", new ArrayList<NameValuePair>(Arrays.asList(pairs)));
			logger.info("Received post from HttpHelper");
			//Logs the user into the server
			helper.check_get_after_post = true;
			try {
				JSONObject result_object = new JSONObject(helper.postResponsefromURL("/login", new ArrayList<NameValuePair>(Arrays.asList(pairs))));
				logger.info(result_object.toString());
				if(!result_object.has("email")){
					logger.error("The returned object is invalid. Returning error");
					returned_error = true;
				}
			} catch (JSONException e) {
				//Don't log the user in if there was an error with the get request
				logger.error("The returned JSON object is super fucked. Returning error");
				returned_error = true;
				e.printStackTrace();
			}
			}
			return null;
		}
		
		@Override
	    protected void onPostExecute(Void v) {
			logger.info("Intent Starting: " + String.valueOf(intent_started));
			logger.info("Passing Class: " + String.valueOf(pass_class));
			logger.info("Returned Error: " + String.valueOf(returned_error));
			logger.info("Test Login: " + String.valueOf(test_login));
			 if(!intent_started && pass_class && (!returned_error || test_login)){
				 logger.info("Starting New Activity...");
				 Intent myIntent = new Intent(context, next_activity);
				 intent_started = true;
				 context.startActivity(myIntent);
			 }else{
				 logger.warning("Login Authentication Failed!");
				 Toast.makeText(context, "Login Authentication Failed! Please Try Again", Toast.LENGTH_LONG).show();	
			 }
		}
	}
	
	//Make sure that the network is active and working...
	private class log_out_network_task extends AsyncTask<Void, Void, Void> {
		
		Handler handler = null;
		JSONObject result_array = null;
		boolean returned_error = false;
		
		@Override
        protected void onPreExecute() {
			logger.info("Network Logout Task Init");
		}
		
		@Override
		protected Void doInBackground(Void... container) {
			synchronized (helper) {
				try {
					logger.info("Requesting logout");
					result_array = new JSONObject(helper.getResponsefromURL("/logout"));
					logger.info("Logout returned array: " + result_array.toString());
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					logger.error("Error: " + e);
					returned_error = true;
					e.printStackTrace();
				}
			}
			logger.info("Logout Returning");
			return null;
		}
		
		@Override
	    protected void onPostExecute(Void arg0) {
			 //The data needs to be saved into the database here...
			if(handler != null){
				if(returned_error){
					logger.warning("There was an error with the request. Keep user logged in.");
					handler.sendEmptyMessage(5);
				}else{
					logger.info("Request valid. Logging user out");
					handler.sendEmptyMessage(4);
				}
			}else{
				logger.error("Return handler is null!");
			}
		}
	}
	
	//Make sure that the network is active and working...
	private class apply_for_credentials extends AsyncTask<Void, Void, Void> {
		ClassUserCredentials credentials;
		Handler handler = null;
		
		@Override
        protected void onPreExecute() {
			logger.info("Apply for credentials init");
		}
		
		@Override
		protected Void doInBackground(Void... pairs) {
			synchronized (helper) {
			//Logs the user into the server
			helper.check_get_after_post = true;
			try {
				logger.info("Requesting data");
				JSONObject result_object = new JSONObject(helper.postResponsefromURL("/login", new ArrayList<NameValuePair>()));
				logger.info("Received data from HttpHelper");
				logger.info(result_object.toString());
				if(!result_object.has("email")){
					credentials.name = "Logged Out";
					credentials.email = "Logged Out";
					credentials.profile_pic = "";
					credentials.rank = -1;
					credentials.logged_in = false;
				}else{
					credentials.name = result_object.get("name").toString();
					credentials.email = result_object.get("email").toString();
					if(result_object.has("picture")){
						credentials.profile_pic = result_object.get("picture").toString();
					}else{
						credentials.profile_pic = "";
					}
					credentials.rank = Integer.valueOf(result_object.get("rank").toString());
					credentials.logged_in = true;
				}
				
			} catch (JSONException e) {
				//Don't log the user in if there was an error with the get request
				logger.error("JSON exception! Error: " + e);
				credentials.logged_in = false;
				e.printStackTrace();
			}
			}
			return null;
		}
		
		@Override
	    protected void onPostExecute(Void v) {
			applying = false;
			if(handler != null){
				logger.info("Returning credentials");
				handler.sendEmptyMessage(5);
			}else{
				logger.error("Return handler cannot be null");
			}
		}
	}
}
